home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 21 / CU Amiga Magazine's Super CD-ROM 21 (1998)(EMAP Images)(GB)[!][issue 1998-04].iso / CUCD / Programming / RTGMaster / demos / moon / WORLD.C < prev    next >
C/C++ Source or Header  |  1996-03-05  |  19KB  |  650 lines

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <time.h>
  4. #include <math.h>
  5. #include <string.h>
  6.  
  7. #include "random.h"
  8. #include "world.h"
  9.  
  10. #define _MAKE_CRATERS
  11. #define _USE_ROUGHNESS_MAP
  12. //#define _BIZARRE_ROUGHNESS_MAP
  13. //#define _BIZARRE_ALT_MAP
  14. //#define DEBUG
  15.  
  16. //----------------------------------------------------------------------------
  17. // The maps.  Note that, in this module, the color_map array is used during
  18. // the generation of the altitude map, so in that case, it is misnamed.
  19. //----------------------------------------------------------------------------
  20.  
  21. map_t    far          alt_map;
  22. map_t    far          color_map;
  23.  
  24. //----------------------------------------------------------------------------
  25. // An internal temporary map used in generating the other maps:
  26. //----------------------------------------------------------------------------
  27.  
  28. static map_t  temp_map;
  29.  
  30. //----------------------------------------------------------------------------
  31. // Assertion code for this module:
  32. //----------------------------------------------------------------------------
  33.  
  34. #ifdef DEBUG
  35.  
  36.    static void     _Assert
  37.    (
  38.       const char * file,
  39.       unsigned     line,
  40.       const char * assertion
  41.    )
  42.    {
  43.       fflush (stdout);
  44.       fprintf ( stderr, "\nAssertion failed (%s, line %u): %s\n",
  45.                 file, line, assertion );
  46.       fflush (stderr);
  47.       abort ();
  48.    }
  49.  
  50.    #define ASSERT(f) if (f) {} else _Assert ( __FILE__, __LINE__, #f )
  51.  
  52. #else
  53.  
  54.    #define ASSERT(f)
  55.  
  56. #endif
  57.  
  58. //----------------------------------------------------------------------------
  59. // FUNCTION  rough_init
  60. //----------------------------------------------------------------------------
  61.  
  62. #ifdef _USE_ROUGHNESS_MAP
  63.  
  64. static void        rough_init
  65. (
  66.    void
  67. )
  68. {
  69.    int  x, y;
  70.  
  71.    for ( x = 0; x < map_size_x; x += 64 )
  72.    {
  73.       for ( y = 0; y < map_size_y; y += 64 )
  74.       {
  75.          color_map [x][y] = (unsigned char) (random ( 128 ) + 80);
  76.       }
  77.    }
  78. }
  79.  
  80. #endif
  81.  
  82. //----------------------------------------------------------------------------
  83. // FUNCTION  map_init
  84. //----------------------------------------------------------------------------
  85.  
  86. static void        map_init
  87. (
  88.    void
  89. )
  90. {
  91.    int  x, y;
  92.  
  93.    for ( x = 0; x < map_size_x; x += 64 )
  94.    {
  95.       for ( y = 0; y < map_size_y; y += 64 )
  96.       {
  97.          color_map [x][y] = (unsigned char) random ( 256 );
  98.       }
  99.    }
  100. }
  101.  
  102. //----------------------------------------------------------------------------
  103. // FUNCTION  flat_area
  104. //----------------------------------------------------------------------------
  105.  
  106. static void        flat_area(
  107.    int             map_x,
  108.    int             map_y,
  109.    int             size_x,
  110.    int             size_y,
  111.    int             height_offset/* = 0 */
  112. )
  113. {
  114.    int             height;
  115.    int             x, y;
  116.  
  117.    // First get the average height of the original rectangular region.
  118.  
  119.    height = 0;
  120.  
  121.    for ( x = 0; x < size_x; ++ x ){
  122.       for ( y = 0; y < size_y; ++ y ){
  123.          height +=
  124.             (int) alt_map [(x+map_x) & clip_mask_x][(y+map_y) & clip_mask_y];
  125.       }
  126.    }
  127.  
  128.    height /= size_x * size_y;
  129.  
  130.    // Offset from the average height.
  131.  
  132.    height += height_offset;
  133.    if      ( height < min_alt   )  height = min_alt;
  134.    else if ( height > max_alt-1 )  height = max_alt - 1;
  135.  
  136.    // Put in the landing pad.
  137.  
  138.    for ( x = 0; x < size_x; ++ x ){
  139.       for ( y = 0; y < size_y; ++ y ){
  140.          alt_map [(x+map_x) & clip_mask_x][(y+map_y) & clip_mask_y] =
  141.             (unsigned char) (height + random (2));
  142.       }
  143.    }
  144. }
  145.  
  146. //----------------------------------------------------------------------------
  147. // FUNCTION  quonset_hut
  148. //----------------------------------------------------------------------------
  149. // These quonset huts run parallel to the Y axis.
  150. //----------------------------------------------------------------------------
  151.  
  152. static void        quonset_hut
  153. (
  154.    int             map_x,
  155.    int             map_y,
  156.    int             size_y
  157. )
  158. {
  159.    int             average;
  160.    int             x, y;
  161.    int r_squared;
  162.    const           radius = 4;
  163.  
  164.    // First get the average height of the original region.
  165.  
  166.    average = 0;
  167.  
  168.    for ( x = 0; x < radius * 2; ++ x ){
  169.       for ( y = 0; y < size_y; ++ y ){
  170.          average +=alt_map [(x+map_x) & clip_mask_x][(y+map_y) & clip_mask_y];
  171.       }
  172.    }
  173.  
  174.    average /= size_y * radius * 2;
  175.  
  176.    // Bury the quonset hut a bit.
  177.  
  178.    average -= scale_area / scale_height;
  179.  
  180.    // Build the hut.
  181.  
  182.    r_squared = radius * radius;
  183.  
  184.    for ( x = 0; x < radius * 2; ++ x ){
  185.       int height =
  186.          (int) sqrt ( (double) (r_squared - (x-radius)*(x-radius) + 1) );
  187.       height *= (scale_area / scale_height);
  188.       height += average;
  189.       if ( height > max_alt ) height = max_alt;
  190.  
  191.       for ( y = 0; y < size_y; ++ y ){
  192.          alt_map [(x+map_x) & clip_mask_x][(y+map_y) & clip_mask_y] =(unsigned char) height;
  193.       }
  194.    }
  195. }
  196.  
  197. //----------------------------------------------------------------------------
  198. // FUNCTION  generate_roughness_map
  199. //----------------------------------------------------------------------------
  200.  
  201. #ifdef _USE_ROUGHNESS_MAP
  202.  
  203. static void generate_roughness_map(void)
  204. {
  205.    int counter = 0;
  206.    int which   = 0;
  207.    int square_size,x1,y1;
  208.    printf ( "  Roughness map:    0 %%" );
  209.  
  210.    rough_init ();
  211.  
  212.    for ( square_size = 64; square_size > 1; square_size /= 2 ){
  213.       for (  x1 = 0; x1 < map_size_x; x1 += square_size ) {
  214.          for ( y1 = 0; y1 < map_size_y; y1 += square_size ) {
  215.             // Get the four influential points.
  216.  
  217.             int x2 = (x1 + square_size) & clip_mask_x;
  218.             int y2 = (y1 + square_size) & clip_mask_y;
  219.  
  220.             int i1, i2, i3, i4;
  221.             int p1,p2,p3,p4;
  222.             int random_center,random_range;
  223.  
  224.             if ( which == 0 )
  225.             {
  226.                i1 = color_map [x1][y1];
  227.                i2 = color_map [x2][y1];
  228.                i3 = color_map [x1][y2];
  229.                i4 = color_map [x2][y2];
  230.             }else{
  231.                i1 = alt_map [x1][y1];
  232.                i2 = alt_map [x2][y1];
  233.                i3 = alt_map [x1][y2];
  234.                i4 = alt_map [x2][y2];
  235.             }
  236.  
  237.             // Obtain new points by averaging the influential points.
  238.  
  239.             p1 = ((i1 * 9) + (i2 * 3) + (i3 * 3) + (i4)) / 16;
  240.             p2 = ((i1 * 3) + (i2 * 9) + (i3) + (i4 * 3)) / 16;
  241.             p3 = ((i1 * 3) + (i2) + (i3 * 9) + (i4 * 3)) / 16;
  242.             p4 = ((i1) + (i2 * 3) + (i3 * 3) + (i4 * 9)) / 16;
  243.  
  244.             // Add a random offset to each new point.
  245.  
  246.             random_center = square_size;
  247.             random_range  = random_center * 2;
  248.  
  249.             #ifdef _BIZARRE_ROUGHNESS_MAP
  250.  
  251.                p1 += random (random_center) + random_range - (max_alt - p1)/6;
  252.                p2 += random (random_center) + random_range - (max_alt - p2)/6;
  253.                p3 += random (random_center) + random_range - (max_alt - p3)/6;
  254.                p4 += random (random_center) + random_range - (max_alt - p4)/6;
  255.  
  256.             #else
  257.  
  258.                p1 += random (random_range) - random_center;
  259.                p2 += random (random_range) - random_center;
  260.                p3 += random (random_range) - random_center;
  261.                p4 += random (random_range) - random_center;
  262.  
  263.             #endif
  264.  
  265.             // Boundary check the altitudes.  Under the normal condition,
  266.             // altitudes that are out of range will be "reflected" back into
  267.             // the allowable range.  Under the bizarre condition, we do
  268.             // something bizarre!
  269.  
  270.             #ifdef _BIZARRE_ROUGHNESS_MAP
  271.  
  272.                p1 = (p1 < min_alt) ? max_alt + p1 + 1 : p1;
  273.                p2 = (p2 < min_alt) ? max_alt + p2 + 1 : p2;
  274.                p3 = (p3 < min_alt) ? max_alt + p3 + 1 : p3;
  275.                p4 = (p4 < min_alt) ? max_alt + p4 + 1 : p4;
  276.  
  277.                p1 = (p1 > max_alt) ? (p1 % (max_alt+1)) : p1;
  278.                p2 = (p2 > max_alt) ? (p2 % (max_alt+1)) : p2;
  279.                p3 = (p3 > max_alt) ? (p3 % (max_alt+1)) : p3;
  280.                p4 = (p4 > max_alt) ? (p4 % (max_alt+1)) : p4;
  281.  
  282.             #else
  283.  
  284.                p1 = (p1 < min_alt) ? (min_alt - p1) + min_alt : p1;
  285.                p2 = (p2 < min_alt) ? (min_alt - p2) + min_alt : p2;
  286.                p3 = (p3 < min_alt) ? (min_alt - p3) + min_alt : p3;
  287.                p4 = (p4 < min_alt) ? (min_alt - p4) + min_alt : p4;
  288.  
  289.                p1 = (p1 > max_alt) ? (max_alt - p1) + max_alt : p1;
  290.                p2 = (p2 > max_alt) ? (max_alt - p2) + max_alt : p2;
  291.                p3 = (p3 > max_alt) ? (max_alt - p3) + max_alt : p3;
  292.                p4 = (p4 > max_alt) ? (max_alt - p4) + max_alt : p4;
  293.  
  294.             #endif
  295.  
  296.             // Write out the generated points.
  297.  
  298.             x2 = (x1 + square_size/2) & clip_mask_x;
  299.             y2 = (y1 + square_size/2) & clip_mask_y;
  300.  
  301.             if ( which == 0 ){
  302.                alt_map   [x1][y1] = (unsigned char) p1;
  303.                alt_map   [x2][y1] = (unsigned char) p2;
  304.                alt_map   [x1][y2] = (unsigned char) p3;
  305.                alt_map   [x2][y2] = (unsigned char) p4;
  306.             }else {
  307.                color_map [x1][y1] = (unsigned char) p1;
  308.                color_map [x2][y1] = (unsigned char) p2;
  309.                color_map [x1][y2] = (unsigned char) p3;
  310.                color_map [x2][y2] = (unsigned char) p4;
  311.             }
  312.  
  313.             counter += 100;
  314.          }
  315.          {
  316.            int percent_done = (int) ( counter / 87360 );
  317.            printf ( "\b\b\b\b\b%3d %%", percent_done );
  318.          }
  319.       }
  320.  
  321.       which = (which == 0) ? 1 : 0;
  322.    }
  323.  
  324.    if ( which == 0 ){
  325.       memcpy ( temp_map, color_map, sizeof (temp_map) );
  326.    }else{
  327.       memcpy ( temp_map, alt_map, sizeof (temp_map) );
  328.    }
  329.  
  330.    printf ( "\b\b\b\b\bdone \n" );
  331. }
  332.  
  333. #endif
  334.  
  335. //----------------------------------------------------------------------------
  336. // FUNCTION  generate_alt_map
  337. //----------------------------------------------------------------------------
  338.  
  339. static void  generate_alt_map(void)
  340. {
  341.    int which   = 0;
  342.    int counter = 0;
  343.    int square_size,i,x,y,x1,y1;
  344.  
  345.    #ifdef _USE_ROUGHNESS_MAP
  346.  
  347.       generate_roughness_map ();
  348.  
  349.    #endif
  350.  
  351.    printf ( "  Altitude map:     0 %%" );
  352.    fflush ( stdout );
  353.  
  354.    map_init ();
  355.  
  356.  
  357.    for ( square_size = 64; square_size > 1; square_size /= 2 ){
  358.       #ifdef _MAKE_CRATERS
  359.  
  360.          if ( square_size == 8 || square_size == 4 ){
  361.             for ( i = 0; i < map_size_x * 3; ++ i ){
  362.                if ( which == 0 )
  363.                   color_map [random (map_size_x)][random (map_size_y)]
  364.                      = (unsigned char) random (32);
  365.                else
  366.                   alt_map [random (map_size_x)][random (map_size_y)]
  367.                      = (unsigned char) random (32);
  368.             }
  369.          }
  370.  
  371.       #endif
  372.  
  373.       // Make pseudo-valley floors.
  374.  
  375.       if ( square_size == 2 ){
  376.          for (  x = 0; x < map_size_x; ++ x ){
  377.             for (  y = 0; y < map_size_y; ++ y ){
  378.                const cutoff_point = (max_alt+1) / 4;
  379.  
  380.                if ( alt_map [x][y] < cutoff_point ){
  381.                   alt_map [x][y] = (unsigned char) (cutoff_point - alt_map [x][y]/2);
  382.                }
  383.             }
  384.          }
  385.       }
  386.  
  387.       for (  x1 = 0; x1 < map_size_x; x1 += square_size ) {
  388.          for (  y1 = 0; y1 < map_size_y; y1 += square_size ){
  389.             // Get the four influential points.
  390.  
  391.             int x2 = (x1 + square_size) & clip_mask_x;
  392.             int y2 = (y1 + square_size) & clip_mask_y;
  393.  
  394.             int i1, i2, i3, i4;
  395.             int p1,p2,p3,p4;
  396.             int random_center,random_range;
  397.  
  398.             if ( which == 0 ){
  399.                i1 = color_map [x1][y1];
  400.                i2 = color_map [x2][y1];
  401.                i3 = color_map [x1][y2];
  402.                i4 = color_map [x2][y2];
  403.             } else {
  404.                i1 = alt_map [x1][y1];
  405.                i2 = alt_map [x2][y1];
  406.                i3 = alt_map [x1][y2];
  407.                i4 = alt_map [x2][y2];
  408.             }
  409.  
  410.             // Obtain new points by averaging the influential points.
  411.  
  412.             p1 = ((i1 * 9) + (i2 * 3) + (i3 * 3) + (i4)) / 16;
  413.             p2 = ((i1 * 3) + (i2 * 9) + (i3) + (i4 * 3)) / 16;
  414.             p3 = ((i1 * 3) + (i2) + (i3 * 9) + (i4 * 3)) / 16;
  415.             p4 = ((i1) + (i2 * 3) + (i3 * 3) + (i4 * 9)) / 16;
  416.  
  417.             // Add a random offset to each new point.
  418.  
  419.             #ifdef _USE_ROUGHNESS_MAP
  420.                random_center = square_size * temp_map [x1][y1] / 84;
  421.             #else
  422.                random_center = square_size * 2;
  423.             #endif
  424.  
  425.             random_range = random_center * 2;
  426.  
  427.             #ifdef _BIZARRE_ALT_MAP
  428.  
  429.                p1 += ( random ( random_range ) - random_center + p1/4 );
  430.                p2 += ( random ( random_range ) - random_center + p2/4 );
  431.                p3 += ( random ( random_range ) - random_center + p3/4 );
  432.                p4 += ( random ( random_range ) - random_center + p4/4 );
  433.  
  434.             #else
  435.  
  436.                p1 += ( random ( random_range ) - random_center );
  437.                p2 += ( random ( random_range ) - random_center );
  438.                p3 += ( random ( random_range ) - random_center );
  439.                p4 += ( random ( random_range ) - random_center );
  440.  
  441.             #endif
  442.  
  443.             // Boundary checking
  444.  
  445.             p1 = (p1 < min_alt) ? (min_alt - p1) + min_alt : p1;
  446.             p2 = (p2 < min_alt) ? (min_alt - p2) + min_alt : p2;
  447.             p3 = (p3 < min_alt) ? (min_alt - p3) + min_alt : p3;
  448.             p4 = (p4 < min_alt) ? (min_alt - p4) + min_alt : p4;
  449.  
  450.             #ifdef _BIZARRE_ALT_MAP
  451.  
  452.                p1 = (p1 > max_alt) ? (p1 - (max_alt+1)) : p1;
  453.                p2 = (p2 > max_alt) ? (p2 - (max_alt+1)) : p2;
  454.                p3 = (p3 > max_alt) ? (p3 - (max_alt+1)) : p3;
  455.                p4 = (p4 > max_alt) ? (p4 - (max_alt+1)) : p4;
  456.  
  457.             #else
  458.  
  459.                p1 = (p1 > max_alt) ? (max_alt - p1) + max_alt : p1;
  460.                p2 = (p2 > max_alt) ? (max_alt - p2) + max_alt : p2;
  461.                p3 = (p3 > max_alt) ? (max_alt - p3) + max_alt : p3;
  462.                p4 = (p4 > max_alt) ? (max_alt - p4) + max_alt : p4;
  463.  
  464.             #endif
  465.  
  466.             // Write out the generated points.
  467.  
  468.             x2 = (x1 + square_size/2) & clip_mask_x;
  469.             y2 = (y1 + square_size/2) & clip_mask_y;
  470.  
  471.             if ( which == 0 ){
  472.                alt_map [x1][y1]   = (unsigned char) p1;
  473.                alt_map [x2][y1]   = (unsigned char) p2;
  474.                alt_map [x1][y2]   = (unsigned char) p3;
  475.                alt_map [x2][y2]   = (unsigned char) p4;
  476.             } else{
  477.                color_map [x1][y1] = (unsigned char) p1;
  478.                color_map [x2][y1] = (unsigned char) p2;
  479.                color_map [x1][y2] = (unsigned char) p3;
  480.                color_map [x2][y2] = (unsigned char) p4;
  481.             }
  482.  
  483.             counter += 100;
  484.          }
  485.          {
  486.            int percent_done = (int) ( counter / 87360 );
  487.            printf ( "\b\b\b\b\b%3d %%", percent_done );
  488.          }
  489.       }
  490.  
  491.       which = (which == 0) ? 1 : 0;
  492.    }
  493.  
  494.    if ( which == 0 ){
  495.       memcpy ( alt_map, color_map, map_size_x * map_size_y );
  496.    }
  497.  
  498.    // Create some man-made features in the landscape.
  499.  
  500.    flat_area   ( 0,  0,  20, 20,0 );
  501.    quonset_hut ( 0,  20, 24 );
  502.  
  503.    // We're done!
  504.  
  505.    printf ( "\b\b\b\b\bdone \n" );
  506.    fflush ( stdout );
  507. }
  508.  
  509. //----------------------------------------------------------------------------
  510. // FUNCTION  calc_color_map
  511. //----------------------------------------------------------------------------
  512.  
  513. static void  calc_color_map( void)
  514. {
  515.    int x,  y;
  516.    int color;
  517.    int percent_done;
  518.  
  519.    int * shadow;
  520.  
  521.    shadow = (int *) calloc ( map_size_y, sizeof (int) );
  522.    ASSERT ( shadow != NULL );
  523.  
  524.    printf ( "  Shading map:      0 %%" );
  525.    fflush ( stdout );
  526.  
  527.    for ( x = 0; x < map_size_x; ++ x ) {
  528.       for ( y = 0; y < map_size_y; ++ y ) {
  529.          int slope = alt_map [x][y] - alt_map [(x-1)&clip_mask_x][y];
  530.  
  531.          slope *= 2;
  532.          slope += 40;
  533.  
  534.          if ( slope < 0  ) slope = 0;
  535.          if ( slope > 63 ) slope = 63;
  536.  
  537.          color = slope + 1;
  538.  
  539.          color_map [x][y] = (unsigned char) color;
  540.       }
  541.  
  542.       percent_done = x * 24 / map_size_x;
  543.  
  544.       printf ( "\b\b\b\b\b%3d %%", percent_done );
  545.    }
  546.  
  547.    // Cast shadows.
  548.  
  549.    for ( y = 0; y < map_size_y; ++ y ) {
  550.       shadow [y] = (int) alt_map [0][y];
  551.    }
  552.  
  553.    for ( x = 1; x < map_size_x; ++ x ) {
  554.       for ( y = 0; y < map_size_y; ++ y )  {
  555.          int height;
  556.          shadow [y] -= 3;
  557.          if ( shadow [y] < 0 )  shadow [y] = 0;
  558.  
  559.          height = (int) alt_map [x][y];
  560.  
  561.          if ( height >= shadow [y] ) {
  562.             shadow [y] = height;
  563.  
  564.             temp_map [x][y] = 0;
  565.          } else {
  566.             temp_map [x][y] = 1;
  567.          }
  568.       }
  569.  
  570.       percent_done = x * 23 / map_size_x + 24;
  571.  
  572.       printf ( "\b\b\b\b\b%3d %%", percent_done );
  573.    }
  574.  
  575.    for ( x = 0; x < 128; ++ x ) {
  576.       for ( y = 0; y < map_size_y; ++ y ) {
  577.          int height;
  578.          shadow [y] -= 3;
  579.          if ( shadow [y] < 0 )  shadow [y] = 0;
  580.  
  581.          height = (int) alt_map [x][y];
  582.  
  583.          if ( height >= shadow [y] ){
  584.             shadow [y] = height;
  585.  
  586.             temp_map [x][y] = 0;
  587.          } else {
  588.             temp_map [x][y] = 1;
  589.          }
  590.       }
  591.  
  592.       percent_done = x * 6 / map_size_x + 47;
  593.  
  594.       printf ( "\b\b\b\b\b%3d %%", percent_done );
  595.    }
  596.  
  597.    for ( x = 0; x < map_size_x; ++ x ){
  598.       for ( y = 0; y < map_size_y; ++ y ){
  599.          if ( temp_map [x][y] ){
  600.             int color = (int) color_map [x][y];
  601.             color -= 18;
  602.             if ( color < 1 )
  603.                color = 1;
  604.             color_map [x][y] = (unsigned char) color;
  605.          }
  606.       }
  607.  
  608.       percent_done = x * 23 / map_size_x + 53;
  609.  
  610.       printf ( "\b\b\b\b\b%3d %%", percent_done );
  611.    }
  612.  
  613.    // Average the map colors to make the map appear smoother.
  614.  
  615.    for ( x = 0; x < map_size_x; ++ x ){
  616.       for ( y = 0; y < map_size_y; ++ y ){
  617.          color  = 6 * color_map [x][y];
  618.          color += 4 * color_map [(x+1) & clip_mask_x][y];
  619.          color += 4 * color_map [x][(y+1) & clip_mask_y];
  620.          color += 2 * color_map [(x+1) & clip_mask_x][(y+1) & clip_mask_y];
  621.  
  622.          color /= 16;
  623.  
  624.          color_map [x][y] = (unsigned char) color;
  625.       }
  626.  
  627.       percent_done = x * 24 / map_size_x + 76;
  628.  
  629.       printf ( "\b\b\b\b\b%3d %%", percent_done );
  630.    }
  631.  
  632.    free (shadow);
  633.  
  634.    printf ( "\b\b\b\b\bdone \n" );
  635.    fflush ( stdout );
  636. }
  637.  
  638. //----------------------------------------------------------------------------
  639. // FUNCTION  WORLD_generate
  640. //----------------------------------------------------------------------------
  641.  
  642. void WORLD_generate (void )
  643. {
  644.    printf ( "\nGenerating the moonscape...\n\n" );
  645.  
  646.    randomize        ();
  647.    generate_alt_map ();
  648.    calc_color_map   ();
  649. }
  650.